package org.ndx.jsg.output.freemarker;

import java.io.File;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.ndx.jsg.FileInfos;
import org.ndx.jsg.RelativePathProvider;

/**
 * Representation of a directory
 * @author ndx
 *
 */
public class Directory implements RelativePathProvider {
	/**
	 * Node name (well, directory name)
	 */
	private final String name;
	
	private final String relativePath;
	/**
	 * List of file infos in this directory
	 */
	private Collection<FileInfos> files = new LinkedList<FileInfos>();
	/**
	 * List of sub-directories
	 */
	private Map<String, Directory> directories = new TreeMap<String, Directory>();

	private NameResolver resolver;

	private String relativeDepth;
	
	public Directory(String dir, String relativePath, String relativeDepth) {
		name = dir;
		this.relativePath = relativePath;
		this.relativeDepth = relativeDepth;
	}

	public void accept(DirectoryVisitor v) {
		v.startVisit(this);
		for(Directory d : directories.values()) {
			d.accept(v);
		}
		for(FileInfos f : files) {
			v.visit(f);
		}
		v.endVisit(this);
	}
	
	/**
	 * Add at given coordinates the given file
	 * @param asList
	 * @param infos
	 */
	public void addAt(List<String> coordinates, FileInfos infos) {
		if(coordinates.size()==0) {
			files.add(infos);
		} else {
			String dir;
			while((dir = coordinates.remove(0)).trim().length()==0) {
				
			}
			if(!directories.containsKey(dir)) {
				directories.put(dir, new Directory(dir, getRelativePath()+File.separator+dir, ".."+File.separator+getRelativeDepth()));
			}
			directories.get(dir).addAt(coordinates, infos);
		}
	}

	public String getName() {
		return name;
	}

	/**
	 * Get directory relative path
	 * @return
	 */
	@Override
	public String getRelativePath() {
		return relativePath;
	}
	
	public String getRelativeDepth() {
		return relativeDepth;
	}
	
	/**
	 * Get string from template name
	 * @param templateName
	 * @return name of file associated to template name
	 */
	public String getUrl(String templateName) {
		return resolver.resolve(this, templateName, false);
	}
	
	/**
	 * Get url associated to file by applying the given template name from the given relative path.
	 * @param relativePath a path separated using {@link File#separator}. Notice it must be a path to a file, not a path to a directory
	 * @param templateName a template name corresponding to {@link TemplateApplier#resolveFileName(String, String, String)}
	 * @return the shortest possible relative path
	 */
	public String getUrl(String relativePath, String templateName) {
		String relativeUrl = getUrl(templateName);
		return Utils.compress(relativePath, relativeUrl).replace(File.separator, "/");
	}

	public NameResolver getResolver() {
		return resolver;
	}

	public void setResolver(NameResolver resolver) {
		this.resolver = resolver;
		for(Directory d: directories.values()) {
			d.setResolver(resolver);
		}
	}
	
	public Collection<Directory> getDirectories() {
		return directories.values();
	}
}